package com.crazymakercircle.im.common.codec;

import com.crazymakercircle.im.common.bean.msg.ProtoMsg;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;

/**
 * <p>Title: ProtobufDecoder</p>
 * （1）首先读取长度，如果长度位数不够，则终止读取。
 * （2）然后读取魔数、版本号等其他的字段。
 * （3）最后按照净长度读取内容。如果内容的字节数不够，则恢复到之前的起始位置（也就是长度的位置），然后终止读取。
 *
 * @author: dwLiu
 * @date: 2021/11/23 17:43
 */
public class ProtobufDecoder extends ByteToMessageDecoder {
    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
        //标记一下当前的读指针readIndex位置
        byteBuf.markReaderIndex();
        //判断包头的长度，不够包头的长度
        if (byteBuf.readableBytes() < 2) {
            return;
        }
        //读取传送过来的消息长度
        int length = byteBuf.readShort();
        //如果长度小于0
        if (length < 0) {
            channelHandlerContext.close();//非法数据，关闭连接
        }
        //可读字节数小于预期消息长度
        if (length > byteBuf.readableBytes()) {
            //重置读取位置
            byteBuf.resetReaderIndex();
            return;
        }
        //省略：读取魔数、版本号等其他的数据
        //省略：读取内容
        byte[] array;
        //堆缓冲
        if (byteBuf.hasArray()) {
            ByteBuf slice = byteBuf.slice();
            array = slice.array();
            //直接缓冲
        } else {
            array = new byte[length];
            byteBuf.readBytes(array, 0, length);
        }
        //字节转车ProtoBuf的pojo对象
        ProtoMsg.Message outMsg = ProtoMsg.Message.parseFrom(array);
        if (outMsg != null) {
            //ProtoBuf的POJO实例加入到出站List内容
            list.add(outMsg);
        }
    }
}
